package org.myspringmvc.web.servlet;

import jakarta.servlet.ServletConfig;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.myspringmvc.web.constant.Const;
import org.myspringmvc.web.context.WebApplicationContext;

import java.io.IOException;
import java.net.URLDecoder;
import java.nio.charset.Charset;
import java.util.Locale;

public class DispatcherServlet extends HttpServlet {
    /**
     * 视图解析器
     */
    private ViewResolver viewResolver;
    /**
     * 处理器映射器
     */
    private HandlerMapping handlerMapping;
    /**
     * 处理器适配器
     */
    private HandlerAdapter handlerAdapter;

    @Override
    public void init() throws ServletException {
        //找到springmvc.xml文件
        /**
         * <init-param>
         *     <param-name>contextConfigLocation</param-name>
         *     <param-value>classpath:springmvc.xml</param-value>
         * </init-param>
         */
        //config对象是tomcat服务器创建的
        ServletConfig servletConfig = this.getServletConfig();
        String contextConfigLocation = servletConfig.getInitParameter(Const.CONTEXT_CONFIG_LOCATION).trim();
        System.out.println("contextConfigLocation : " + contextConfigLocation);
        String springMvcConfigPath = null;
        if (contextConfigLocation.startsWith(Const.PRE_CLASSPATH)) {
            //获取springmvc配置文件的绝对路径
            springMvcConfigPath = Thread.currentThread().getContextClassLoader()
                    .getResource(contextConfigLocation.substring(Const.PRE_CLASSPATH.length()))
                    .getPath();
            //对路径中的特殊字符进行解码
            springMvcConfigPath = URLDecoder.decode(springMvcConfigPath, Charset.defaultCharset());
            System.out.println("springMvcConfigPath : " + springMvcConfigPath);
        }
        //初始化Spring Web容器， 初始化ApplicationContext上下文对象
        WebApplicationContext webApplicationContext = new WebApplicationContext(springMvcConfigPath, this.getServletContext());
        //将WebApplicationContext对象存入ServletContext中，便于后续使用
        this.getServletContext().setAttribute(Const.WEB_APPLICATION_CONTEXT, webApplicationContext);
        //属性初始化
        this.viewResolver = (ViewResolver) webApplicationContext.getBean(Const.VIEW_RESOLVER);
        this.handlerMapping = (HandlerMapping) webApplicationContext.getBean(Const.HANDLER_MAPPING);
        this.handlerAdapter = (HandlerAdapter) webApplicationContext.getBean(Const.HANDLER_ADAPTER);

    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        doDispatch(req, resp);
    }

    /**
     * 处理请求的核心方法
     *
     * @param request
     * @param response
     * @throws ServletException
     * @throws IOException
     */
    private void doDispatch(HttpServletRequest request, HttpServletResponse response) {
        try {
            //1.根据请求对象获取对应的处理器执行对象
            HandlerExecutionChain mappedHandler = handlerMapping.getHandler(request);
            //2.根据处理器方法获取对应的处理器适配器对象
            HandlerAdapter ha = this.handlerAdapter;
            //3.执行拦截器中的preHandle方法
            if (!mappedHandler.applyPreHandle(request, response)) {
                return;
            }
            //4.执行处理器方法，并返回ModelAndView对象,第三个参数是HandlerMethod
            ModelAndView mv = ha.handle(request, response, mappedHandler.getHandler());
            //5.执行拦截器中的postHandle方法
            mappedHandler.applyPostHandle(request, response, mv);
            //6.响应
            //通过视图解析器进行解析，返回View对象
            View view = viewResolver.resolveViewName(mv.getView().toString(), Locale.CHINA);
            //渲染
            view.render(mv.getModel(), request, response);
            //7.执行拦截器中的afterCompletion方法
            mappedHandler.triggerAfterCompletion(request,response,null);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
